#pragma once

#include "ann_m.h"
#include "ann_pre.h"

namespace ann
{

class net
{
public:
    net(void)
    : m_status(0),
      m_alpha(0.6),
      m_criEk(0.008),
      m_inCnt(0),
      m_outCnt(0)
    {
        m_lStruct.clear();
        m_nodes.clear();
        m_trData.clear();
    }

    virtual ~net(void);

public:
    virtual const   UINT    Init ( const wchar_t* pInitFile )                 = 0;
    virtual const   UINT    Reset( void )                                     = 0;
    virtual const   UINT    Train( void )                                     = 0;
    virtual const   UINT    Sim  ( const dVec& pInVec, dVec* pOutVec = NULL ) = 0;

    virtual const   UINT    InitFromFile(const wchar_t* pInitFile)          = 0;

protected:
    virtual const   UINT    TestConverge() = 0;

public:
    virtual const   UINT    LoadTRDataFromFile(const wchar_t* ptrDataFilePath);
    virtual const   double  CalEk(const dVec& pObjVec);

    inline const UINT PushTrainData(const TRData& ptrData)
    {
        TRData* trData = new TRData();
        
        trData->m_inVec = ptrData.m_inVec;
        trData->m_outVec = ptrData.m_outVec;
        trData->m_ek = EK_INIT_VAL;

        m_trData.push_back(trData);

        return m_status;
    }

    inline const bool IsConverged()
    {
        return m_status&eann_Converged;   
    }

    inline const UINT GetNodeIdx(const UINT pL, const UINT pLIdx)
    {
        assert( pL != 0 );
        assert( pLIdx>=0 && pLIdx<m_lStruct[pL] );

        UINT offset = 0;
        for( UINT i = 1; i < pL; ++i )
        {
            offset += m_lStruct[i];
        }

        return offset + pLIdx;
    }

public:
    GETTER  (m_status, UINT  )
    ACCESSOR(m_alpha,  double)
    ACCESSOR(m_criEk,  double)
    GETTER  (m_inCnt,  UINT  )
    GETTER  (m_outCnt, UINT  )

    GETTER  (m_lStruct, uVec )
    GETTER  (m_nodes,   npVec)
    ACCESSOR(m_trData,  trVec)

protected:
    UINT   m_status;
    double m_alpha;
    double m_criEk;
    uVec   m_lStruct; // [0] for input layer cnt, and [size-1] for output layer cnt
    npVec  m_nodes;
    trVec  m_trData;

    //for convient
    UINT   m_inCnt;
    UINT   m_outCnt;
};

}
